package SharedDrawing;

/*
 * This file is part of shared-drawing.
 * shared-drawing is free software: you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option )
 * any later version. shared-drawing is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 * You should have received a copy of the GNU General Public License along with 
 * shared-drawing. If not, seehttp://www.gnu.org/licenses/.
 */

import common.XmlConstants;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

/**
 * generate an XML document from drawings or actions (chat, join...)
 * 
 */
public class XmlGenerator{
    
    /**
     * creates a document from a list of ShapeContent
     * @param pageId the page which the user drawn
     * @param attributes the list of WgContent
     * @return the document
     */
    public static Document toXml(Integer pageId, List<ShapeContent> attributes)
    {
        Element root = new Element(XmlConstants.createDrawing);
        root.setAttribute(XmlConstants.pageId, pageId.toString());
        
        Document doc = new Document(root);
        for(ShapeContent content : attributes)
        {
            root.addContent(toXml(content));
        }
        return doc;
    }
    
    public static void sendXml(Integer pageId, List<ShapeContent> attributes)
    {
        SocketClient.getInstance().sendData(XmlGenerator.toXml(pageId, attributes));
    }
    
    public static Document toXml(Integer pageId, ShapeContent content)
    {
        Element root = new Element(XmlConstants.createDrawing);
        root.setAttribute(XmlConstants.pageId, pageId.toString());
        Document doc = new Document(root);
        root.addContent(toXml(content));
        return doc;
    }
    
    public static void sendXml(Integer pageId, ShapeContent content)
    {
        SocketClient.getInstance().sendData(XmlGenerator.toXml(pageId, content));
    }
    
    /**
     * creates a document from an Action
     * @see Action
     * @param action the action to write in XML
     * @return the XML document
     */
    public static Document toXml(Action action)
    {
        Element root = new Element(action.getType());
        Document doc = new Document(root);
        if(action != null)
        {
            for(String key : action.keySet())
            {
                root.setAttribute(key, action.get(key));
            }
        }
        return doc;
    }
    
    public static void sendXml(Action action)
    {
        SocketClient.getInstance().sendData(XmlGenerator.toXml(action));
    }
    
    public static Document toXml(Collection<Page> pages)
    {
        //create the document and its root
        //LATER : use lastId to manage conflicts
        Element root = new Element(XmlConstants.pageCollection);
        root.setAttribute(XmlConstants.pageCollectionLastId, 
                Pages.getInstance().getLastMessage().toString());
        Document doc = new Document(root);
        //for each page
        for(Page page : pages)
        {
            //create new page element
            Element newPage = new Element(XmlConstants.createPage);
            newPage.setAttribute(XmlConstants.pageName, page.getName());
            newPage.setAttribute(XmlConstants.pageOld, page.getId().toString());
            newPage.setAttribute(XmlConstants.creatorId, page.getCreator());
            root.addContent(newPage);
            //and add all wgcontent
            Element child = new Element(XmlConstants.createDrawing);
            child.setAttribute(XmlConstants.pageId, page.getId().toString());
            newPage.addContent(child);
            if(!page.getContent().isEmpty())
            {
                for(ShapeContent content : page.getContent())
                {
                    child.addContent(toXml(content));
                }
            }
        }
        return doc;
    }
    
    public static void sendXml(Collection<Page> pages)
    {
        SocketClient.getInstance().sendData(XmlGenerator.toXml(pages));
    }
    
    public static Document toXml(HashMap<String, String> users)
    {
        Element root = new Element(XmlConstants.users);
        Document doc = new Document(root);
        for(String id : users.keySet())
        {
            Element user = new Element(XmlConstants.joinWorkgroup);
            user.setAttribute(XmlConstants.emitterId, id);
            user.setAttribute(XmlConstants.emitterNickName, 
                    ConnexionManager.getInstance().getNickName(id));
            root.addContent(user);
        }
        return doc;
    }
    
    public static void sendXml(HashMap<String, String> users)
    {
        SocketClient.getInstance().sendData(XmlGenerator.toXml(users));
    }
    
    public static Document toXml(Collection<Page> pages, boolean im_useless)
    {
        Element root = new Element(XmlConstants.viewers);
        Document doc = new Document(root);
        for(Page page : pages){
            List<String> viewers = page.getViews();
            String pageId = page.getId().toString();
            for(String viewer : viewers)
            {
                Element pageView = new Element(XmlConstants.openPage);
                pageView.setAttribute(XmlConstants.pageId, pageId);
                pageView.setAttribute(XmlConstants.viewerId, viewer);
                root.addContent(pageView);
            }
        }
        return doc;
    }
    
    public static Document toXml(String emitterId)
    {
        //create a document that contains all informations about the workgroup
        Element root = new Element(XmlConstants.askUpToDate);
        root.setAttribute(XmlConstants.emitterId, emitterId);
        Document toGive = new Document(root);
        //add all users
        root.addContent(XmlGenerator.toXml(
                ConnexionManager.getInstance().getUserList()).
                getRootElement().detach());
        //add all pages
        Collection<Page> pages = Pages.getInstance().getPages().values();
        root.addContent(
                XmlGenerator.toXml(pages)
                .getRootElement().detach());
        //add all people who has a page open
        root.addContent(XmlGenerator.toXml(pages, true).getRootElement().detach());
        return toGive;
    }
    
    public static void sendXml(String emitterId)
    {
        SocketClient.getInstance().sendData(XmlGenerator.toXml(emitterId));
    }
    
    /**
     * tool to create an XML element from a WgContent
     * @param self the WgContent to write in XML
     * @return an XML Element
     */
    private static Element toXml(WgContent self, String type)
    {
        Element toAdd = new Element(type);
        toAdd.setAttribute(XmlConstants.wgContentType, self.getType());
        for(String key : self.keySet())
        {
            toAdd.setAttribute(key, self.get(key));
        }
        return toAdd;
    }
    
    public static Element toXml(ShapeContent self)
    {
        Element root = toXml(self.getBoundingBox(), XmlConstants.shapeContent);
        for(WgContent content : self.getElementsList())
        {
            root.addContent(toXml(content, XmlConstants.wgContent));
        }
        return root;
    }
    
    public static ShapeContent fromXml(Element xmlShape){
        //creat a new ShapeContent
        ShapeContent shape = new ShapeContent();
        WgContent boundingBox = new WgContent(xmlShape.getAttributeValue(XmlConstants.shapeContentType));
        shape.setBoundingBox(boundingBox);
        for(Attribute attribute : xmlShape.getAttributes())
        {
            if(! XmlConstants.shapeContentType.equals(attribute.getName()))
            {
                boundingBox.addContent(attribute.getName(), attribute.getValue());
            }
        }
        //add its wgContent
        for(Element wg : xmlShape.getChildren(XmlConstants.wgContent))
        {
            //create a new one
            WgContent wgContent = new WgContent(wg.getAttributeValue(XmlConstants.wgContentType));
            //get all attributes
            for(Attribute attribute : wg.getAttributes())
            {
                wgContent.addContent(attribute.getName(), attribute.getValue());
            }
            //add to the shape
            shape.addElement(wgContent);
        }
        return shape;
    }

    private static void printDocument(Document doc) {
        XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
        String string = outputter.outputString(doc);
        System.out.println("document : " +string);
    }
}
